package fr.upmc.aladyn.transactionables.javassist.metaobject;

import java.lang.annotation.Annotation;

import fr.upmc.aladyn.transactionables.annotations.Transactionable;
import fr.upmc.aladyn.transactionables.saveobject.SaveManager;
import javassist.tools.reflect.Metaobject;

/**
 * <p>Class used to modify the comportement of an Object by using Metaobject</p>
 * @author Alexis Deluze
 *
 */
public class TransactionableMetaobject extends Metaobject {

private static final long serialVersionUID = 1L;

	/**
	 * Constructor
	 * @param self
	 * @param args
	 */
	public TransactionableMetaobject(Object self, Object[] args) {
		super(self, args);
	}

	/**
	 * <p>Trap a method call to save the method's class Fields. Restore the Fields if an Exception was thrown during the method's run.</p>
	 * @param identifier the identifier of the method trapped
	 * @param args the arguments of the method trapped
	 * @return the result of the method trapped
	 * @throws Throwable
	 * @see javassist.tools.reflect.Metaobject#trapMethodcall(int, java.lang.Object[])
	 */
	@Override
	public Object trapMethodcall(int identifier, Object[] args) throws Throwable {
	
		Annotation[] annotations;
		boolean isTransactionable = false;
		
		// setters
		if (super.getMethodName(identifier).startsWith("set")) {
			System.out.println("[METAOBJ] Setter "+super.getMethodName(identifier));
			SaveManager.getManager().save(super.getObject());
			return super.trapMethodcall(identifier, args);
		}
		
		// methode @Transactionable
		annotations = super.methods[identifier].getAnnotations();
		for (Annotation annotation : annotations) {
			if (annotation instanceof Transactionable) {
				isTransactionable = true;
					break;
			}
		}
		if (isTransactionable) {
			System.out.println("[METAOBJ] Methode Transactionable "+super.getMethodName(identifier));
			SaveManager.getManager().newStackBlock();
			try {
				Object tmp = super.trapMethodcall(identifier, args);
				SaveManager.getManager().pop();
				return tmp;
			} catch (Exception e) {
				System.out.println("[METAOBJ] Restoration");
				SaveManager.getManager().restore();
				SaveManager.getManager().pop();
				throw e;
			}
		} else {
			return super.trapMethodcall(identifier, args);
		}
	}
}